package com.cwj.mansysback.dao;

import com.cwj.mansysback.dao.impl.TeacherDaoImpl;
import com.cwj.mansysback.dao.util.JdbcUtil;
import com.cwj.mansysback.entity.Pack;
import com.cwj.mansysback.entity.People;
import com.cwj.mansysback.servlet.util.MyUtils;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

public class BaseDao<T> {


    public long update(Connection conn,String sql, Object... args){
        try (Connection con = JdbcUtil.getConnection();
             final PreparedStatement ps = con.prepareStatement(sql)) {

            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            return ps.executeLargeUpdate();

        } catch (SQLException | IOException | ClassNotFoundException throwables) {
            throwables.printStackTrace();
        }

        return -1;
    }


    public long update(String sql, Object... args) {
        try(Connection con = JdbcUtil.getConnection();){
            return this.update(con,sql,args);
        } catch (SQLException | IOException | ClassNotFoundException throwables) {
            throwables.printStackTrace();
        }
        return -1;
    }

    public T select(Connection con,Class<T> clazz, String sql, Object... args){
        T t = null;

        try (

                PreparedStatement ps = con.prepareStatement(sql);
        ) {

            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }

            ResultSet res = ps.executeQuery();

            ps.getMetaData();

            if (res.next()) {

                Constructor<T> constructor = clazz.getConstructor();

                t = constructor.newInstance();

                ResultSetMetaData metaData = res.getMetaData();

                int columnCount = metaData.getColumnCount();

                for (int i = 0; i < columnCount; i++) {

                    String columnLabel = metaData.getColumnLabel(i + 1);

                    Object val = res.getObject(i + 1);

                    if (val == null) continue;

                    Method method = null;

                    try {

                        method = clazz.getMethod(MyUtils.getMethodName(columnLabel), val.getClass());

                        method.invoke(t, val);

                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                        // 查询的结果集中出现了实体没有出现过的属性，就跳过这个字段,且因为是最后一条指令所以可以不加
                        continue;
                    }


                }

            }


        } catch (SQLException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException throwables) {
            throwables.printStackTrace();
        }

        return t;
    }

    //    仅仅获得查询到的第一个对象
    public T select(Class<T> clazz, String sql, Object... args) {
            try( Connection con = JdbcUtil.getConnection();){
                return this.select(con,clazz,sql,args);
            } catch (SQLException | IOException | ClassNotFoundException throwables) {
                throwables.printStackTrace();
            }
            return null;
    }

    public List<T> selectBatch(Connection con, Class<T> clazz, String sql, Object... args){
        List<T> res = new ArrayList<>();

        try (

                final PreparedStatement ps = con.prepareStatement(sql);

        ) {

            for (int i = 0; i < args.length; i++) {

                ps.setObject(i + 1, args[i]);

            }

            final ResultSet resultSet = ps.executeQuery();

            final ResultSetMetaData metaData = resultSet.getMetaData();

            final int columnCount = metaData.getColumnCount();

            List<String> colLabelsMethodName = new ArrayList<>();

            final Constructor<T> constructor;

            constructor = clazz.getConstructor();


            for (int i = 0; i < columnCount; i++) {
                colLabelsMethodName.add(MyUtils.getMethodName(metaData.getColumnLabel(i + 1)));
            }

            Method method = null;

            for (int i = 0; i < columnCount; i++)

                while (resultSet.next()) {

                    T t = null;

                    t = constructor.newInstance();

                    for (int j = 0; j < columnCount; j++) {

                        Object val = resultSet.getObject(j + 1);

                        if (val == null) continue;

                        try {

                            method = clazz.getMethod(colLabelsMethodName.get(j), val.getClass());

                            method.invoke(t, val);

                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        }

                    }

                    res.add(t);

                }

        } catch (SQLException | NoSuchMethodException |
                InstantiationException | IllegalAccessException | InvocationTargetException throwables) {
            throwables.printStackTrace();
        }

        return res;
    }

    public List<T> selectBatch(Class<T> clazz, String sql, Object... args) {

        try(Connection con = JdbcUtil.getConnection();){
            return this.selectBatch(con,clazz,sql,args);
        } catch (SQLException | IOException | ClassNotFoundException throwables) {
            throwables.printStackTrace();
        }
        return new ArrayList<>();
    }


    public long updateBatch(String sql, Object[][] objects) {

        long res_count = 0;

        boolean flag = true;

//        Connection con = null;
        Connection con = null;

        PreparedStatement ps = null;

        try {

            con = JdbcUtil.getConnection();

            ps = con.prepareStatement(sql);

            flag = con.getAutoCommit();

            con.setAutoCommit(false);

            for (int i = 0; i < objects.length; i++) {
                for (int j = 0; j < objects[i].length; j++) {

                    ps.setObject(j + 1, objects[i][j]);

                }
                ps.addBatch();

                if ((i + 1) % 500 == 0) {
                    res_count += Arrays.stream(ps.executeLargeBatch()).sum();

                    ps.clearBatch();
                }
            }

            res_count += Arrays.stream(ps.executeLargeBatch()).sum();

            con.commit();

            con.setAutoCommit(flag);

        } catch (SQLException | IOException | ClassNotFoundException throwables) {
            throwables.printStackTrace();

        } finally {
            try {
                JdbcUtil.close(ps, con, flag);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        return res_count;

    }

    public long updateBatch(String sql, List<List<Object>> objects) {

        long res_count = 0;

        boolean flag = true;

//        Connection con = null;
        Connection con = null;

        PreparedStatement ps = null;

        try {

            con = JdbcUtil.getConnection();

            ps = con.prepareStatement(sql);

            flag = con.getAutoCommit();

            con.setAutoCommit(false);

            for (int i = 0; i < objects.size(); i++) {
                for (int j = 0; j < objects.get(i).size(); j++) {

                    ps.setObject(j + 1, objects.get(i).get(j));

                }
                ps.addBatch();

                if ((i + 1) % 500 == 0) {
                    res_count += Arrays.stream(ps.executeLargeBatch()).sum();

                    ps.clearBatch();
                }
            }

            res_count += Arrays.stream(ps.executeLargeBatch()).sum();

            con.commit();

            con.setAutoCommit(flag);

        } catch (SQLException | IOException | ClassNotFoundException throwables) {
            throwables.printStackTrace();

        } finally {
            try {
                JdbcUtil.close(ps, con, flag);
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        return res_count;

    }

    public static Pack selectAllPack(String tableName ,Integer accrank) {

        if(accrank < 0){
            String sql = "select count(*) count from " +tableName;
            return new BaseDao<Pack>().select(Pack.class,sql.toString());
        }

        String sql = "select count(*) count from " +tableName + "\twhere accrank = ?";

        return new BaseDao<Pack>().select(Pack.class,sql,accrank);
    }

    public static void main(String[] args) {
        System.out.println(BaseDao.selectAllPack("teacher",2));
    }




}
